#pragma once

#include <atomic>
#include <chrono>
#include <functional>
#include <memory>
#include <optional>
#include <thread>
#include <utility>

#include "lf_queue.hpp"      // 提供固定容量的 Lock-Free 队列原型。
#include "thread_utils.hpp"  // 提供 createAndStartThread 等线程工具。

namespace Common {

// 自定义 deleter：专门搭配 std::unique_ptr<std::thread> 使用，
// 在销毁 unique_ptr 时，先 join 线程再 delete 避免资源泄漏。
struct ThreadDeleter {
  void operator()(std::thread* t) const noexcept {
    if (t) {
      if (t->joinable()) {
        t->join();
      }
      delete t;
    }
  }
};

// ----------- 生产者工具函数 -----------

/**
 * @brief 非阻塞生产接口，若队列被认为“满”则立即失败。
 *
 * @param queue    目标 LFQueue。
 * @param capacity 队列容量（因 LFQueue 当前无 size/capacity 区分，需外部传入）。
 * @param value    待写入的数据。
 * @return true 写入成功；false 队列已满。
 *
 * @note 这里用 size() 判断是否达到容量，仅适用于单生产者语义。
 */
template <typename T>
bool tryProduce(LFQueue<T>& queue, std::size_t capacity, const T& value) {
  if (queue.size() >= capacity) {
    return false;
  }
  *queue.getNextToWriteTo() = value;
  queue.updateWriteIndex();
  return true;
}

/**
 * @brief 阻塞式写入，直到有空槽位才成功返回。
 *
 * @param queue    目标 LFQueue。
 * @param capacity 队列容量。
 * @param value    待写入的数据。
 *
 * @note 通过自旋 + std::this_thread::yield() 避免过度占用 CPU。
 *       若需要更复杂的等待策略，可替换为 sleep 或条件变量。
 */
template <typename T>
void produce(LFQueue<T>& queue, std::size_t capacity, const T& value) {
  while (!tryProduce(queue, capacity, value)) {
    std::this_thread::yield();
  }
}

// ----------- 消费者工具函数 -----------

/**
 * @brief 非阻塞读取，若队列为空返回 std::nullopt。
 *
 * @param queue 目标 LFQueue。
 * @return std::optional<T> 读取成功返回元素副本，失败返回 std::nullopt。
 *
 * @note 读取流程：检查 size() -> getNextToRead() 拿到指针 -> 拷贝 -> updateReadIndex()。
 */
template <typename T>
std::optional<T> tryConsume(LFQueue<T>& queue) {
  if (queue.size() == 0) {
    return std::nullopt;
  }
  const T* slot = queue.getNextToRead();
  T copy = *slot;
  queue.updateReadIndex();
  return copy;
}

/**
 * @brief 阻塞式读取，直到队列中有元素可取。
 *
 * @param queue 目标 LFQueue。
 * @return 读取到的元素副本。
 *
 * @note 同样采用自旋机制；如需节流可加入 sleep。
 */
template <typename T>
T consume(LFQueue<T>& queue) {
  while (true) {
    if (auto item = tryConsume(queue)) {
      return *std::move(item);
    }
    std::this_thread::yield();
  }
}

// ----------- 简易消费者启动/句柄 -----------

/**
 * @brief 消费线程句柄，用于 stop/join。
 *
 * worker      持有消费者线程的 unique_ptr，由 ThreadDeleter 管理生命周期。
 * requestStop 外部可调用以请求线程退出（通过原子标志实现）。
 */
struct ConsumerHandle {
  std::unique_ptr<std::thread, ThreadDeleter> worker;
  std::function<void()> requestStop;

  /// 请求消费者线程结束循环（线程内部检测标志后会自行退出）。
  void stop() const {
    if (requestStop) {
      requestStop();
    }
  }

  /// 主动等待线程结束：reset 会触发 deleter，执行 join + delete。
  void join() {
    worker.reset();
  }
};

/**
 * @brief 启动一个消费循环线程，持续从 LFQueue 取元素并交给回调处理。
 *
 * @tparam T        队列元素类型。
 * @tparam Callback 可调用对象类型，签名需能接受一个 T（值或常值引用）。
 * @param queue     被消费的 LFQueue。
 * @param cb        每次成功消费元素后的回调。
 * @param idleSleep 当队列暂时为空时休眠的时间间隔，避免忙等。
 * @param core_id   线程绑定的 CPU 核心，默认 -1 表示不绑定。
 * @param name      线程名称，供调试日志或亲和性设置使用。
 * @return ConsumerHandle 供外部 stop/join。
 *
 * @note
 *  - 该函数假定单消费者语义；
 *  - 回调会在消费线程中执行，注意线程安全。
 */
template <typename T, typename Callback>
ConsumerHandle startConsumer(LFQueue<T>& queue,
                             Callback&& cb,
                             std::chrono::milliseconds idleSleep = std::chrono::milliseconds{1},
                             int core_id = -1,
                             std::string name = "consumer") {
  auto running = std::make_shared<std::atomic<bool>>(true);

  // 消费线程主体：不断尝试消费；为空则短暂休眠；收到停止信号后排空剩余元素。
  auto loop = [running, &queue, cb = std::forward<Callback>(cb), idleSleep]() mutable {
    while (running->load(std::memory_order_acquire)) {
      if (auto item = tryConsume(queue)) {
        cb(std::move(*item));
      } else {
        std::this_thread::sleep_for(idleSleep);
      }
    }
    while (auto item = tryConsume(queue)) {
      cb(std::move(*item));
    }
  };

  ConsumerHandle handle;
  // createAndStartThread 返回裸指针，这里用 unique_ptr 托管，避免手动 delete。
  handle.worker = std::unique_ptr<std::thread, ThreadDeleter>(
      createAndStartThread(core_id, std::move(name), loop));
  // stop() 实际上就是把 running 标志置为 false，线程循环就会自然退出。
  handle.requestStop = [running]() {
    running->store(false, std::memory_order_release);
  };

  return handle;
}

}  // namespace Common